package edu.gatech.gro;

import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseExpandableListAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import edu.gatech.gro.http.IResponseAdapter;
import edu.gatech.gro.model.Currency;
import edu.gatech.gro.model.GroceryStore;
import edu.gatech.gro.model.Item;
import edu.gatech.gro.model.ItemType;
import edu.gatech.gro.model.ListGroup;
import edu.gatech.gro.model.ListItem;
import edu.gatech.gro.model.ObjectResponse;
import edu.gatech.gro.utils.Utils;

public class ItemLookUpActivity extends Activity {

	/* Tag For Log Cat */
	private static final String TAG = "ITEM_LOOKUP_ACTIVITY";
	/* Constants */
	private static final int GOT_ITEM_TYPES = 0;
	private static final int GOT_GROCERY_STORES = 1;
	private static final int GOT_SEARCH_RESULTS = 2;

	private static final int ITEM_CREATED = 10;
	private static final int ITEM_ADDED = 11;

	/* Handler */
	private final IncomingHandler mHandler = new IncomingHandler();

	/* Main Class */
	private static GroceryListManagerApplication app;

	/* View Variables */
	private EditText mItemAdderSearchText;
	private ExpandableListView mResults;
	private LinearLayout mAdderFieldsLayout;
	private Spinner mItemAdderStoreChooser;
	private Spinner mItemAdderTypeChooser;
	private Spinner mItemAdderCurrencyChooser;
	private EditText mItemAdderPriceText;
	private Button mItemAdderAddButton;

	private AlertDialog mAlertDialog;
	private ProgressDialog mProgressSearch;
	private ProgressDialog mProgressAddingItem;

	/* Others */
	private String mCurrentSearch;
	private ArrayList<ListGroup> mCurrentResults;
	private ArrayList<ListGroup> mOriginalResults;
	private ArrayList<ItemType> mCurrentItemTypes;
	private ArrayList<GroceryStore> mCurrentGroceryStores;

	private int mListId;
	private String mListNameClean;
	private String mLastFilter;
	private SearchItemAdapter mSearchItemAdapter;
	private Item mLastCreatedItem;

	/**
	 * onCreate Create the main view of the search screen
	 */

	@Override
	public void onCreate(Bundle bundle) {
		super.onCreate(bundle);

		app = (GroceryListManagerApplication) getApplicationContext();
		setContentView(R.layout.search_manager);

		mLastFilter = "";
		mItemAdderSearchText = (EditText) findViewById(R.id.itemAdderSearchText);
		mResults = (ExpandableListView) findViewById(R.id.expandableListSearchResults);
		mAdderFieldsLayout = (LinearLayout) findViewById(R.id.itemAdderFieldsLayout);
		mItemAdderStoreChooser = (Spinner) findViewById(R.id.itemAdderGroceryChooser);
		mItemAdderTypeChooser = (Spinner) findViewById(R.id.itemAdderTypeChooser);
		mItemAdderCurrencyChooser = (Spinner) findViewById(R.id.itemAdderCurrencyChooser);
		mItemAdderPriceText = (EditText) findViewById(R.id.itemAdderPriceText);
		mItemAdderAddButton = (Button) findViewById(R.id.itemAdderAddButton);

		Bundle extra = getIntent().getExtras();
		mListId = extra.getInt("namedList_id");
		mListNameClean = extra.getString("namedList_nameClean");

		mAlertDialog = new AlertDialog.Builder(ItemLookUpActivity.this).create();
		mAlertDialog.setButton(this.getString(R.string.ok), new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();
			}
		});

		mItemAdderAddButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				Log.d(TAG, "Save clicked!");
				waitForSavingItem();
			}
		});

		mItemAdderSearchText.addTextChangedListener(new TextWatcher() {

			@Override
			public void onTextChanged(CharSequence s, int start, int before, int count) {
				String name = Utils.cleanName(mItemAdderSearchText.getText().toString());
				if (name.length() > 2) {
					String s1 = name.substring(0, 3);
					String s2 = mLastFilter.length() > 2 ? mLastFilter.substring(0, 3) : "";
					if (!s1.equals(s2)) {
						mCurrentSearch = name;
						waitForSearch();
					} else if (mOriginalResults != null && mOriginalResults.size() > 0) {
						if (name.startsWith(mLastFilter) && mCurrentResults.size() == 0) {
							// Do NOT search
						} else {
							Log.d(TAG, "Filtering results");
							filterResults(name);
						}
					}
					mLastFilter = name;
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count, int after) {
				// TODO Auto-generated method stub

			}

			@Override
			public void afterTextChanged(Editable s) {
				// TODO Auto-generated method stub

			}
		});

		ArrayAdapter<String> currencyAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, Currency.allSymbols());
		mItemAdderCurrencyChooser.setAdapter(currencyAdapter);

		waitForItemTypes();
		waitForGroceryStores();
	}

	@Override
	public void onResume() {
		super.onResume();
	}

	private void waitForItemTypes() {
		// Hidden by default. Progress bar should be useless
		app.getAllItemTypes(mItemTypesListener);
	}

	private void waitForGroceryStores() {
		// Hidden by default. Progress bar should be useless
		app.getAllGroceryStores(mGroceryStoresListener);
	}

	private void waitForSearch() {
		if (mProgressSearch != null && mProgressSearch.isShowing()) {
			return;
		}
		if (!mCurrentSearch.equals(mLastFilter)) {
			mProgressSearch = ProgressDialog.show(ItemLookUpActivity.this, "", this.getString(R.string.progressSearchItem), true, false);
			app.searchItem(mCurrentSearch, mSearchListener);
		}
	}

	private void waitForAddingListItem(final ListItem item) {
		if (mProgressAddingItem != null && mProgressAddingItem.isShowing()) {
			return;
		}

		mProgressSearch = ProgressDialog.show(ItemLookUpActivity.this, "", this.getString(R.string.progressAddingItem), true, false);
		app.addItemToNamedList(mListNameClean, item, mItemAddedListener);
	}

	private boolean waitForSavingItem() {
		if (mProgressAddingItem != null && mProgressAddingItem.isShowing()) {
			return false;
		}

		Item item = new Item();
		item.setName(mItemAdderSearchText.getText().toString());
		item.setGroceryStoreId(mCurrentGroceryStores.get(mItemAdderStoreChooser.getSelectedItemPosition()).getId());
		item.setItemTypeId(mCurrentItemTypes.get(mItemAdderTypeChooser.getSelectedItemPosition()).getId());
		item.setBarCode("RANDOM");
		item.setPrice(Double.parseDouble(mItemAdderPriceText.getText().toString()));
		item.setCurrency(mItemAdderCurrencyChooser.getSelectedItemPosition() + 1);

		mProgressAddingItem = ProgressDialog.show(ItemLookUpActivity.this, "", this.getString(R.string.progressItemCreation), true, false);
		app.saveItem(item, mItemSavedListener);
		return true;
	}

	private void askForQuantity(final Item item) {
		ListItem li = new ListItem();
		li.setId(item.getId());
		li.setNamedListId(mListId);
		li.setQuantity(1);
		li.setCurrency(0);
		li.setChecked(false);
		waitForAddingListItem(li);
	}

	private void refreshResults() {
		if (mCurrentResults != null) {
			if (mSearchItemAdapter == null) {
				mSearchItemAdapter = new SearchItemAdapter(mCurrentResults);
				mResults.setAdapter(mSearchItemAdapter);
			} else {
				mSearchItemAdapter.setGroups(mCurrentResults);
				mSearchItemAdapter.notifyDataSetChanged();
			}

			if (mCurrentResults.size() > 0) {
				mResults.setVisibility(View.VISIBLE);
				mAdderFieldsLayout.setVisibility(View.GONE);
			} else {
				mResults.setVisibility(View.GONE);
				mAdderFieldsLayout.setVisibility(View.VISIBLE);
			}
		}
	}

	private void filterResults(String nameClean) {
		if (!nameClean.equals(mLastFilter)) {
			mCurrentResults.clear();
			ArrayList<ListGroup> copy = new ArrayList<ListGroup>();
			for (ListGroup g : mOriginalResults) {
				ArrayList<Item> ni = new ArrayList<Item>();
				for (Item i : g.getItems()) {
					if (i.getNameClean().startsWith(nameClean)) {
						ni.add(i);
					}
				}
				if (ni.size() > 0) {
					ListGroup ng = new ListGroup();
					ng.setId(g.getId());
					ng.setName(g.getName());
					ng.setItems(ni);
					mCurrentResults.add(ng);
				}
			}
			refreshResults();
		}
	}

	private void refreshItemTypes() {
		if (mCurrentItemTypes != null) {
			// mItemAdderTypeChooser.setAdapter(new
			// ItemTypeAdapter(ItemAdder.this,
			// R.layout.spinner_item_type, mCurrentItemTypes));
			String[] array = new String[mCurrentItemTypes.size()];
			for (int i = 0; i < mCurrentItemTypes.size(); i++) {
				array[i] = mCurrentItemTypes.get(i).getName();
			}
			ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, array);
			mItemAdderTypeChooser.setAdapter(adapter);
		}
	}

	private void refreshGroceryStores() {
		if (mCurrentGroceryStores != null) {
			String[] array = new String[mCurrentGroceryStores.size()];
			for (int i = 0; i < mCurrentGroceryStores.size(); i++) {
				array[i] = mCurrentGroceryStores.get(i).getName();
			}
			ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, array);
			mItemAdderStoreChooser.setAdapter(adapter);
		}
	}

	/**
	 * Helper function to dismiss a progress dialog
	 * 
	 * @param theProgress
	 *          the progress dialog to dismiss
	 */
	private void dismissProgress(ProgressDialog theProgress) {
		if (theProgress != null && theProgress.isShowing()) {
			theProgress.dismiss();
		}
	}

	/**
	 * Handler of incoming messages from the Service
	 */
	private class IncomingHandler extends Handler {

		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
				case GOT_ITEM_TYPES:
					refreshItemTypes();
					break;
				case GOT_GROCERY_STORES:
					refreshGroceryStores();
					break;
				case GOT_SEARCH_RESULTS:
					refreshResults();
					break;
				case ITEM_CREATED:
					askForQuantity(mLastCreatedItem);
					break;
				case ITEM_ADDED:
					finish();
					break;
				default:
					super.handleMessage(msg);
					break;
			}
		}
	}

	private final IResponseAdapter mItemTypesListener = new IResponseAdapter() {

		@Override
		public void onResponse(ObjectResponse response) {
			if (response.isSuccessful()) {
				mCurrentItemTypes = (ArrayList<ItemType>) response.getData();

				mHandler.sendEmptyMessage(GOT_ITEM_TYPES);
			} else {
				displayError(R.string.failRetrieveTypesTitle, response.getErrorsAsString());
			}
		}
	};

	private final IResponseAdapter mGroceryStoresListener = new IResponseAdapter() {

		@Override
		public void onResponse(ObjectResponse response) {
			if (response.isSuccessful()) {
				mCurrentGroceryStores = (ArrayList<GroceryStore>) response.getData();

				mHandler.sendEmptyMessage(GOT_GROCERY_STORES);
			} else {
				displayError(R.string.failRetrieveStoresTitle, response.getErrorsAsString());
			}
		}
	};

	private final IResponseAdapter mSearchListener = new IResponseAdapter() {

		@Override
		public void onResponse(ObjectResponse response) {
			dismissProgress(mProgressSearch);
			Log.d(TAG, "Search results!");
			if (response.isSuccessful()) {
				mOriginalResults = (ArrayList<ListGroup>) response.getData();
				mCurrentResults = (ArrayList<ListGroup>) mOriginalResults.clone();
			} else {
				if (mOriginalResults != null) {
					mOriginalResults.clear();
					mCurrentResults.clear();
				} else {
					mOriginalResults = new ArrayList<ListGroup>();
					mCurrentResults = mOriginalResults;
				}
				// displayError(R.string.failSearchItemTitle,
				// response.getErrorsAsString());
			}
			mHandler.sendEmptyMessage(GOT_SEARCH_RESULTS);
		}
	};

	private final IResponseAdapter mItemAddedListener = new IResponseAdapter() {

		@Override
		public void onResponse(ObjectResponse response) {
			dismissProgress(mProgressAddingItem);
			if (response.isSuccessful()) {
				Log.d(TAG, "Item added");
				mHandler.sendEmptyMessage(ITEM_ADDED);
			} else {
				displayError(R.string.failAddItemTitle, response.getErrorsAsString());
			}
		}
	};

	private final IResponseAdapter mItemSavedListener = new IResponseAdapter() {

		@Override
		public void onResponse(ObjectResponse response) {
			dismissProgress(mProgressAddingItem);
			if (response.isSuccessful()) {
				mLastCreatedItem = (Item) response.getData();
				mHandler.sendEmptyMessage(ITEM_CREATED);
			} else {
				displayError(R.string.failCreateItemTitle, response.getErrorsAsString());
			}
		}
	};

	private void displayError(final int titleId, final String message) {
		mAlertDialog.setTitle(titleId);
		mAlertDialog.setMessage(message);
		mAlertDialog.show();
	}

	private class SearchItemAdapter extends BaseExpandableListAdapter {

		private ArrayList<ListGroup> mGroups;

		public SearchItemAdapter(ArrayList<ListGroup> groups) {
			super();
			this.mGroups = groups;
		}

		@Override
		public Item getChild(int groupPosition, int childPosition) {
			return mGroups.get(groupPosition).getItems().get(childPosition);
		}

		@Override
		public long getChildId(int groupPosition, int childPosition) {
			return mGroups.get(groupPosition).getItems().get(childPosition).getId();
		}

		@Override
		public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
			View v = convertView;
			if (v == null) {
				LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				v = vi.inflate(R.layout.search_type_item, null);
			}
			final Item li = getChild(groupPosition, childPosition);
			if (li != null) {
				final TextView textName = (TextView) v.findViewById(R.id.search_type_item_name);
				textName.setText(li.getName());
				textName.setOnClickListener(new View.OnClickListener() {
					@Override
					public void onClick(View v) {
						askForQuantity(li);
					}
				});
			}
			return v;
		}

		@Override
		public int getChildrenCount(int groupPosition) {
			return mGroups.get(groupPosition).getItems().size();
		}

		@Override
		public ListGroup getGroup(int groupPosition) {
			return mGroups.get(groupPosition);
		}

		@Override
		public int getGroupCount() {
			return mGroups.size();
		}

		@Override
		public long getGroupId(int groupPosition) {
			return mGroups.get(groupPosition).getId();
		}

		@Override
		public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
			View v = convertView;
			if (v == null) {
				LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				v = vi.inflate(R.layout.search_type, null);
			}
			final ListGroup g = getGroup(groupPosition);
			if (g != null) {
				TextView textName = (TextView) v.findViewById(R.id.search_type_name);
				textName.setText(g.getName());
			}
			ExpandableListView parentGroup = (ExpandableListView) parent;
			parentGroup.expandGroup(groupPosition);
			return v;
		}

		@Override
		public boolean hasStableIds() {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public boolean isChildSelectable(int groupPosition, int childPosition) {
			// TODO Auto-generated method stub
			return false;
		}

		public void setGroups(ArrayList<ListGroup> groups) {
			this.mGroups = groups;
		}
	}
}
